/**
 * 
 */
package bpel.instructions;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import bpel.BPELProcess;
import bpel.variables.BPELComplexVariable;
import bpel.variables.BPELMessageVariable;
import bpel.variables.BPELStandardVariable;

/**
 * @author Maurice & Topia
 * 
 */
public class BPELCondition {

	public static final int UNKNOWN_SIGN = 0;
	public static final int EQ = 0;
	public static final int NEQ = 1;
	public static final int GT = 2;
	public static final int LT = 3;
	public static final int GTE = 4;
	public static final int LTE = 5;

	public static final String STR_UNKNOWN = "unknown";
	public static final String STR_EQ = "=";
	public static final String STR_NEQ = "!=";
	public static final String STR_GT = ">";
	public static final String STR_LT = "<";
	public static final String STR_GTE = ">=";
	public static final String STR_LTE = "<=";

	/**
	 * Pattern returns (1) left member (2) comparison sign (3) right member
	 */
	private static final String globalRegexp = "([^<=>]*)([<=>][<=>]*)([^<=>]*)";

	/**
	 * Pattern returns (1) function name (2) parameter list (must be split)
	 */
	private static final String functionRegexp = "(.*)\\((.*)\\)"; // returns

	private int compSign;

	private String leftMember;
	private String rightMember;

	public BPELCondition(String condition) {
		compSign = UNKNOWN_SIGN;
		parseCondition(condition);
	}

	private void parseCondition(String condition) {
		Pattern pattern = Pattern.compile(globalRegexp);
		Matcher matcher = pattern.matcher(condition);
		boolean matches = matcher.matches();

		if (matches) {
			this.leftMember = matcher.group(1);
			this.compSign = getCompSignId(matcher.group(2));
			this.rightMember = matcher.group(3);
		} else {
			System.err.println("Condition '" + condition + "' doesn't match to the current regular expression");
		}
	}

	private int getCompSignId(String compSignStr) {

		if (compSignStr.equals(STR_EQ)) {
			return EQ;
		}

		if (compSignStr.equals(STR_GT)) {
			return GT;
		}

		if (compSignStr.equals(STR_GTE)) {
			return GTE;
		}

		if (compSignStr.equals(STR_LT)) {
			return LT;
		}

		if (compSignStr.equals(STR_LTE)) {
			return LTE;
		}

		if (compSignStr.equals(STR_NEQ)) {
			return NEQ;
		}

		return -1;
	}

	private String getCompStr(int compSignId) {

		switch (compSignId) {
		case EQ:
			return STR_EQ;

		case GT:
			return STR_GT;

		case GTE:
			return STR_GTE;

		case LT:
			return STR_LT;

		case LTE:
			return STR_LTE;

		case NEQ:
			return STR_NEQ;

		default:
			return STR_UNKNOWN;
		}

	}

	private boolean isFunction(String member) {
		Pattern pattern = Pattern.compile(functionRegexp);
		Matcher matcher = pattern.matcher(member);
		boolean matches = matcher.matches();

		return matches;
	}

	private String getVariableData(BPELProcess process, String member) {

		// 1 argument -> get variable value
		// 2 arguments -> query an element attribute value
		// 3 arguments -> query a message part element attribute value

		Pattern pattern = Pattern.compile(functionRegexp);
		Matcher matcher = pattern.matcher(member);
		matcher.matches();

		String parameters[] = matcher.group(2).split(",");
		String element;
		String part;
		String query;

		switch (parameters.length) {

		case 1:
			return ((BPELStandardVariable) process.getVariable(parameters[0].trim())).getValue();

		case 2:
			element = parameters[0].trim();
			query = parameters[1].trim();

			return ((BPELComplexVariable) process.getVariable(element)).query(query);

		case 3:
			element = parameters[0].trim();
			part = parameters[1].trim();
			query = parameters[2].trim();

			return ((BPELMessageVariable) process.getVariable(element)).query(part, query);

		default:
			System.err.println("(BPELCondition) Bad argument number for getVariable data expected 1, 2 or 3 got " + parameters.length);
			return null;
		}
	}

	public boolean isTrue(BPELProcess process) {
		String lMemberValue;
		String rMemberValue;

		if (isFunction(leftMember)) {
			lMemberValue = getVariableData(process, leftMember);
		} else {
			if (leftMember.equals("''")) {
				lMemberValue = "''";
			} else {
				lMemberValue = ((BPELStandardVariable) process.getVariable(leftMember)).getValue();
			}
		}

		if (isFunction(rightMember)) {
			rMemberValue = getVariableData(process, rightMember);
		} else {
			if (rightMember.equals("''")) {
				rMemberValue = "''";
			} else {
				rMemberValue = ((BPELStandardVariable) process.getVariable(rightMember)).getValue();
			}
		}

		switch (compSign) {
		case EQ:
			return (lMemberValue.equals(rMemberValue));

		case GT:
			return (Float.parseFloat(lMemberValue) > Float.parseFloat(rMemberValue));

		case GTE:
			return (Float.parseFloat(lMemberValue) >= Float.parseFloat(rMemberValue));

		case LT:
			return (Float.parseFloat(lMemberValue) < Float.parseFloat(rMemberValue));

		case LTE:
			return (Float.parseFloat(lMemberValue) <= Float.parseFloat(rMemberValue));

		case NEQ:
			return (!lMemberValue.equals(rMemberValue));

		default:
			System.err.println("(BPELCondition) Unknown comparison id : '" + compSign + "'");
			return false;
		}
	}

	@Override
	public String toString() {
		return leftMember + " " + getCompStr(compSign) + " " + rightMember;
	}
}
